#ifndef __Sample_Context_H__
#define __Sample_Context_H__


#include "../include/Ogre.h"
#ifdef PU
#include "ParticleUniverseSystemManager.h"
#include "ParticleUniversePlugin.h"
#endif
#include "OgreAnimationState.h"
#include "OgreFrameListener.h"
#include "OgreArchiveMap.h"
#include "Singleton.h"

using namespace Ogre;



class   SampleContext : public CSingleton<SampleContext >, Ogre::FrameListener
{
public:
	SampleContext();
	
	virtual ~SampleContext();

	virtual Ogre::RenderWindow* getRenderWindow()
	{
		return mWindow;
	}
	//
	void Update(float deltaTime);
	//
	void InitMono();
	/*-----------------------------------------------------------------------------
	| Quits the current sample and starts a new one.
	-----------------------------------------------------------------------------*/
	virtual void runSample();

	/*-----------------------------------------------------------------------------
	| Processes frame started events.
	-----------------------------------------------------------------------------*/
	virtual bool frameStarted(const Ogre::FrameEvent& evt)
	{
		captureInputDevices();      // capture input
		return true;
	}
		
	/*-----------------------------------------------------------------------------
	| Processes rendering queued events.
	-----------------------------------------------------------------------------*/
	virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt)
	{
		// manually call sample callback to ensure correct order
		// move the lights along their paths
		for (int i=0;i<mAnimStateList.size();i++)
		{
			mAnimStateList[i]->addTime(evt.timeSinceLastFrame);
		}
		return true;

	}
		
	/*-----------------------------------------------------------------------------
	| Processes frame ended events.
	-----------------------------------------------------------------------------*/
	virtual bool frameEnded(const Ogre::FrameEvent& evt)
	{
		return true;
	}

	/*-----------------------------------------------------------------------------
	| Processes window size change event. Adjusts mouse's region to match that
	| of the window. You could also override this method to prevent resizing.
	-----------------------------------------------------------------------------*/
protected:
	/*-----------------------------------------------------------------------------
	| Configures the startup settings for OGRE. I use the config dialog here,
	| but you can also restore from a config file. Note that this only happens
	| when you start the context, and not when you reset it.
	-----------------------------------------------------------------------------*/
	virtual bool oneTimeConfig()
	{
		return mRoot->showConfigDialog();
		// return mRoot->restoreConfig();
	}

	/*-----------------------------------------------------------------------------
	| Creates the render window to be used for this context. I use an auto-created
	| window here, but you can also create an external window if you wish.
	| Just don't forget to initialise the root.
	-----------------------------------------------------------------------------*/
	virtual void createWindow()
	{
		mWindow = mRoot->initialise(true);
	}

	/*-----------------------------------------------------------------------------
	| Finds context-wide resource groups. I load paths from a config file here,
	| but you can choose your resource locations however you want.
	-----------------------------------------------------------------------------*/
	virtual void locateResources()
	{
		// load resource paths from config file
		Ogre::ConfigFile cf;
		cf.load("resources.cfg");

		Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
		Ogre::String sec, type, arch;

		// go through all specified resource groups
		while (seci.hasMoreElements())
		{
			sec = seci.peekNextKey();
			Ogre::ConfigFile::SettingsMultiMap* settings = seci.getNext();
			Ogre::ConfigFile::SettingsMultiMap::iterator i;

			// go through all resource paths
			for (i = settings->begin(); i != settings->end(); i++)
			{
				type = i->first;
				arch = i->second;
				Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch, type, sec);
			}
		}
	}

	/*-----------------------------------------------------------------------------
	| Loads context-wide resource groups. I chose here to simply initialise all
	| groups, but you can fully load specific ones if you wish.
	-----------------------------------------------------------------------------*/
	virtual void loadResources()
	{
		Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
	}
	/*-----------------------------------------------------------------------------
	| Recovers the last sample after a reset. You can override in the case that
	| the last sample is destroyed in the process of resetting, and you have to
	| recover it through another means.
	-----------------------------------------------------------------------------*/
	virtual void recoverLastSample()
	{
		
	}

	/*-----------------------------------------------------------------------------
	| Cleans up and shuts down the context.
	-----------------------------------------------------------------------------*/
	virtual void shutdown()
	{
		shutdownInput();
	}

	/*-----------------------------------------------------------------------------
	| Destroys OIS input devices and the input manager.
	-----------------------------------------------------------------------------*/
	virtual void shutdownInput()
	{
		
	}

	/*-----------------------------------------------------------------------------
	| Captures input device states.
	-----------------------------------------------------------------------------*/
	virtual void captureInputDevices()
	{

	}

public:	
	// custom shader parameter bindings
	enum ShaderParam { SP_SHININESS = 1, SP_DIFFUSE, SP_SPECULAR };

	Ogre::Root* mRoot;              // OGRE root
	Ogre::RenderWindow* mWindow;    // render window
	bool mSamplePaused;             // whether current sample is paused
	bool mFirstRun;                 // whether or not this is the first run
	bool mLastRun;                  // whether or not this is the final run
	Ogre::String mNextRenderer;     // name of renderer used for next run
	Ogre::NameValuePairList mLastSampleState;     // state of last sample
	//
	Ogre::AnimationState* mGreenLightAnimState;
	Ogre::AnimationState* mYellowLightAnimState;
	Ogre::AnimationState* mAnimStates;
	std::vector<Ogre::AnimationState*> mAnimStateList; 
private:
	//for mono
	/// User objects binding.
	UserObjectBindings mUserObjectBindings;
public:
	UserObjectBindings&	getUserObjectBindings() { return mUserObjectBindings; }
	void setCurAnimStates(AnimationState* AnimStates){ mAnimStates = AnimStates;}
	void addAnimStates(AnimationState* AnimStates);


};

#define SAMPLECONTEXT SampleContext::Instance()

#endif